import math.big

struct IntegerRadix {
	digit_string string
	radix        u32
}

type TestInteger = IntegerRadix | []u8 | big.Integer | i64 | int | string | u32 | u64

fn (a TestInteger) parse() big.Integer {
	return match a {
		big.Integer {
			a
		}
		string {
			big.integer_from_string(a) or { panic('Cannot read decimal') }
		}
		int {
			big.integer_from_int(a)
		}
		u32 {
			big.integer_from_u32(a)
		}
		u64 {
			big.integer_from_u64(a)
		}
		i64 {
			big.integer_from_i64(a)
		}
		[]u8 {
			big.integer_from_bytes(a)
		}
		IntegerRadix {
			big.integer_from_radix(a.digit_string, a.radix) or {
				panic('Cannot read decimal base ${a.radix}')
			}
		}
	}
}

struct IntegerFromTest {
	value    TestInteger
	expected string // prefix with 0x for hex
}

// vfmt off
const integer_from_int_test_data = [
	// use int
	IntegerFromTest{ 0, '0' },
	IntegerFromTest{ 1, '1' },
	IntegerFromTest{ 255, '255' },
	IntegerFromTest{ 127, '127' },
	IntegerFromTest{ 1024, '1024' },
	IntegerFromTest{ 2147483647, '0x7fffffff' },
	IntegerFromTest{ -2147483647, '-2147483647' },
	IntegerFromTest{ -2147483648, '-2147483648' },
]

const integer_from_u64_test_data = [
	// use u64
	IntegerFromTest{ u64(0), '0' },
	IntegerFromTest{ u64(1), '1' },
	IntegerFromTest{ u64(255), '255' },
	IntegerFromTest{ u64(127), '127' },
	IntegerFromTest{ u64(1024), '1024' },
	IntegerFromTest{ u64(4294967295), '0xffffffff' },
	IntegerFromTest{ u64(4398046511104), '0x40000000000' },
	IntegerFromTest{ u64(-1), '0xffffffffffffffff' },
]

const integer_from_bytes_test_data = [
	// use []u8
	IntegerFromTest{ []u8{}, '0' },
	IntegerFromTest{ [u8(0)], '0' },
	IntegerFromTest{ [u8(0x13), 0x37], '0x1337' },
	IntegerFromTest{ [u8(0x13), 0x37, 0xca], '0x1337ca' },
	IntegerFromTest{ [u8(0x13), 0x37, 0xca, 0xfe], '0x1337cafe' },
	IntegerFromTest{ [u8(0x13), 0x37, 0xca, 0xfe, 0xba], '0x1337cafeba' },
	IntegerFromTest{ [u8(0x13), 0x37, 0xca, 0xfe, 0xba, 0xbe], '0x1337cafebabe' },
]

const integer_from_string_test_data = [
	// use string
	IntegerFromTest{ '00000000', '0' },
	IntegerFromTest{ '00', '0' },
	IntegerFromTest{ '0', '0' },
	IntegerFromTest{ '1', '1' },
	IntegerFromTest{ '0012', '12' },
	IntegerFromTest{ '1349173614', '1349173614' },
	IntegerFromTest{ '+24', '24' },
	IntegerFromTest{ '-325', '-325' },
	IntegerFromTest{ '-2147483648', '-2147483648' },
	IntegerFromTest{ '2147483647', '2147483647' },
]

const integer_from_radix_test_data = [
	// use IntegerRadix
	IntegerFromTest{ IntegerRadix{ '101010', 2 }, '42' },
	IntegerFromTest{ IntegerRadix{ '1010', 2 }, '10' },
	IntegerFromTest{ IntegerRadix{ '-0000101', 2 }, '-5' },
	IntegerFromTest{ IntegerRadix{ 'CAFE', 16 }, '0xcafe' },
	IntegerFromTest{ IntegerRadix{ 'DED', 16 }, '0xded' },
	IntegerFromTest{ IntegerRadix{ '-abcd', 16 }, '-43981' },
]
// vfmt on

// is_*
struct IsXTest {
	value    TestInteger
	expected bool
}

// vfmt off
const is_power_of_2_test_data = [
	IsXTest{ "-4", false },
	IsXTest{ u32(0b110000000000), false },
	IsXTest{ "537502395172353242345", false },
	IsXTest{ "590295810358705700000", false },
	IsXTest{ "1125899906842624", true },
	IsXTest{ "590295810358705651712", true },
	IsXTest{ "4611686018427388002", false },
	IsXTest{ "31195165372897259196222538898096203590151924108450147950531565441852619837316692843188389598728651769482088968838700984268947453885587967878549286444999755742573423371025356539077075265986419171772426279084559025861175301940492273427120221755816136975739916983004778387946699939545354293487098252428954036286183995782377175227121587657233553706589448547148066273280603243167958729707736664649187444136702017299877489729451997277875868782399735511520086969969766278182145454186690598629675562422923132555707758646587702550600894625696538109646366308973392363200122154242784576162149305816215109893613161331026672647000825615987247035266514313689413563779184515427920269935280569035788081552413007563772309295149800172031645681720569680154349893907395864528243629654386620034655445226295834594630792819545156798270599481573436039129275439653984521135652249263653985326577886990615665734998585216581730937090703518997669223802429711292740491797911117308280939507973715877108492303860661291987529284719391551256912380499409630332506454532263266457209921483705507359152839264852808182519011100934922492651373859423833024010283468753147686188675294998119637462200763443029190704825719342806119404339670408160210011918981038977425180213726646978883378058838510330816291941879581568740273684084511318422175006728346276489384220596694727036836687670632486602655240593463885077059375085482211864761344849868123074687509143827139683659102930877963676911995751113159944160296419825178911962487549670296207457410515598040046860567719116506974858703739531721991704589155513182996455827177472", true },
]

const is_odd_test_data = [
	IsXTest{ u32(0), false },
	IsXTest{ u32(1), true },
	IsXTest{ u32(1805), true },
	IsXTest{ "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", true },
	IsXTest{ "57495732561923751347562394571325712358054", false },
]
// vfmt on

struct AddTest {
	augend TestInteger
	addend TestInteger
	sum    TestInteger
}

// vfmt off
const add_test_data = [
	AddTest{ 0,  0, 0},
	AddTest{ 1, -1, 0 },
	AddTest{ -1, 1, 0 },
	AddTest{ 0,  2, 2},
	AddTest{ 2, 0, 2 },
	AddTest{ 0, -2, -2},
	AddTest{ -2, 0, -2 },
	AddTest{ 2, -2, 0 },
	AddTest{ -2, 2, 0 },
	AddTest{ -1, 200, 199},
	AddTest{ 200, -1, 199},
	AddTest{ -2, 100, 98},
	AddTest{ 100, -2, 98},
	AddTest{ -100, -2, -102},
	AddTest{ -2, -100, -102},
	//
	AddTest{ 1, 200, 201},
	AddTest{ -200, -1, -201},
	AddTest{ 2, 100, 102},
	AddTest{ -100, -2, -102},
	AddTest{ 100, -2, 98},
	AddTest{ 2, -100, -98},
	//
	AddTest{ 2, 3, 5 },
	AddTest{ 1024, 1024, 2048 },
	AddTest{ 1024, 1024, 2048 },
	AddTest{
		'84885164052257330097714121751630835360966663883732297726369399',
		'137347080577163115432025771710279131845700275212767467264610201',
		'222232244629420445529739893461909967206666939096499764990979600'
	},
]
// vfmt on

struct SubTest {
	minuend    TestInteger
	subtrahend TestInteger
	difference TestInteger
}

// vfmt off
const sub_test_data = [
	SubTest{ 0, 0, 0 },
	SubTest{ 0, -1, 1 },
	SubTest{ -1, 0, -1 },
	SubTest{ 1, 1, 0},
	SubTest{ 1, -1, 2},
	SubTest{ 2, -1, 3},
	SubTest{ -1, 2, -3},
	SubTest{ -100, 100, -200},
	SubTest{ 100, -100, 200},
	SubTest{ -100, -100, 0},
	//
	SubTest{ 1, 200, -199},
	SubTest{ -200, -1, -199},
	SubTest{ 2, 100, -98},
	SubTest{ -100, -2, -98},
	SubTest{ 100, -2, 102},
	SubTest{ 2, -100, 102},
	//
	SubTest{ 2, 3, -1 },
	SubTest{ 3, 2, 1 },
	SubTest{ 1024, 1024, 0 },
	SubTest{ 1025, 1023, 2 },
	SubTest{ -37, -54, 17 },
	SubTest{
		'606649970971701574041811686113740270202550876483709086148210605390116266828180223053050209778348894403980564356645388786075884763988241017548715303094260467104311496756419021350006724017740287475611178032365989622403609173077177580917766063674998982266831659846883191228163839505500376638406380518500245205640396836251745520989267049355350124770273420388742964392659042390255365913227741421167939209094197448839427828553490702868654886044542868294392357965495270538217024561541188096726845410444367476070654975991208949317364651403789852688275944360458918380026777837704864009506175958100724200063354587117724445105352507371251655385818390017704579668464509118556289300149193216670709993199698192433115976551775179800369638443387559604023762303996929773104264181192752852969235821274398832731350067075624797873057893457025900696931888413170836093304160937994690818677414459443711940357617086640671088053946435282979649549418554954712352988774810660384276492179755146895039071579530616412414312102806763864081256558973934032350169887606110957605908487251732839382994454544873238510239304731396067785963044777530602823206256913249732064244398147271369308044244332002083201889676311272588373015273349596481282728910186314212094495644361558295140446865360550851657930415001417226985487444959716363633445225371706716914389021896551395496211883459788574558837045534063579702308219870597512062392856506558380417078205327200246935706335015817156527870338168318120000713685289299174193726065869808768486103389894925715767295',
		'7216848130098425850',
		'606649970971701574041811686113740270202550876483709086148210605390116266828180223053050209778348894403980564356645388786075884763988241017548715303094260467104311496756419021350006724017740287475611178032365989622403609173077177580917766063674998982266831659846883191228163839505500376638406380518500245205640396836251745520989267049355350124770273420388742964392659042390255365913227741421167939209094197448839427828553490702868654886044542868294392357965495270538217024561541188096726845410444367476070654975991208949317364651403789852688275944360458918380026777837704864009506175958100724200063354587117724445105352507371251655385818390017704579668464509118556289300149193216670709993199698192433115976551775179800369638443387559604023762303996929773104264181192752852969235821274398832731350067075624797873057893457025900696931888413170836093304160937994690818677414459443711940357617086640671088053946435282979649549418554954712352988774810660384276492179755146895039071579530616412414312102806763864081256558973934032350169887606110957605908487251732839382994454544873238510239304731396067785963044777530602823206256913249732064244398147271369308044244332002083201889676311272588373015273349596481282728910186314212094495644361558295140446865360550851657930415001417226985487444959716363633445225371706716914389021896551395496211883459788574558837045534063579702308219870597512062392856506558380417078205327200246935706335015817156527870338168318120000713685289299174193726065869808768486096173046795617341445',
	},
]
// vfmt on

struct MulTest {
	multiplicand TestInteger
	multiplier   TestInteger
	product      TestInteger
}

// vfmt off
const mul_test_data = [
	MulTest{ 2, 3, 6 },
	MulTest{ -2, 0, 0},
	MulTest{  2, 0, 0},
	MulTest{ 0, -2, 0},
	MulTest{ 0, -2, 0},
	MulTest{ -869, 789, -685641 },
	MulTest{ 869, -789, -685641 },
	MulTest{ -869, -789, 685641 },
	MulTest{
		'58347508324752098346789015701837509173586123875823769823749056132786590812379812508163208610983759827349812730',
		'14213098571932561236783245987342583245873465877179284713298718093758173895718957198751983759745983467856287759872365123980571298307512352359812753907',
		'829298887246357277468549979504958437413899799327432161171392486113084301523868147373815625368847440980180012682723545766706164916763514684200098693771786210459637448034580321756504306033681868059717237409850393775584813902875585559881251293651935822025836110',
	},
	MulTest{
		'157894047392519583862123936251422583282863434486161035821830453040785097509971311098714713467802515421581208662454854025309513312726555776113715381698473216141765400957534609297819356059233676661532235280302251223761244857785344705006637894902125836430726519102261679054112732204572631900384085596495981525783',
		'172750769107109861232750661741561572021207635860888814481781323903637921618217893620438648685692072759912890797284948206448457977080536627892119852493829355756035584640064060706092098984542716937323104336194056741403356304500304286336281585594296381344018535478383343176463402322692068381151973870461499748949',
		'27276318124492212465432029043652584179286098914879267159076000142724287743892530142734241126306064189405321580796475224876708675570413592358715948396724932685085972846389975012793388131866028332508690735727488135870026351955805826642739703000986587467280495743559787380135296551334471419857554510187338555406214731430906002559624746468831645485763335047438526317636794466414295301915951975626967409997005043887959717124157434636781107429998249363525957258509402650503217872035874896065023377356660153975719637017472701236397203173555796145677008784279961849944450443054513670798899182054747598702569678446196470652067',
	},
	MulTest{
		'164171010688258216356020741663906501410127235530735881272116103087925094171390144280159034536439457734870419127140401667195510331085657185332721089236401193044493457116299768844344303479235489462436380672117015123283299131391904179287678259173308536738761981139958654880852234908448338817289014166774169869251339379828599748492918775437864739032217778051333882990074116246281269364933724892342134504702491040016637557429810893780765197418589477584716543480995722533317862352141459217781316266211186486157019262080414077670264642736018426998113523445732680856144329876972273300703392584997729207197971083945700345494092400147186997307012069454068489589035676979448169848060836924945824197706493306108258511936030341393221586423523264452449403781993352421885094664052270795527632721896121424813173522474674395886155092203404036730748474781710715745446135468098139831824083259647919175273503681561172684624283384438504776503000432241604550454374116320822227191911322123484085063926350606342197146407841178028071147192533942517270553513988142925976090769695456221159699052583533011331652079347093098173086975483539274464023357456484465482927479569437320368592222760278170306076733438801098370797675711274671054970711442158930561684343135774118741612806419906031631601266266528538520924083161856865743302334249701407315310271018388258886432135273827859691733059369978643041918967442197313534697497404277350224866705804878433671262763482023400349043259178916572687989162930903779045078287573241909420120175442471703679516781197223112216572138640838928909745860699538278329256643602865002960800914563144124971099443335826150972157276451120655954671045954561868041854882824297821929166520068974703653272620867577906523992874996338253216963333346753434848676176334066388995978444434383568257588867823277644840815468397633199054967729800149549182806977698239412258835996851311070873503482289001486370524332318228425883088614099902710492272286924686293234474771490822760225994669314033129796588388559938376504519357876526207739824571643922272657401623465041482584188509253569882124046470363144411921518246416624724749905231440644997507666770400152259424985923818812142693481946120458476848688265618957991911827715393356088636270325443851034622105141544646198235918882925122792559855912557079094394123423520644892444598598382078381161104113085486556201098925110067360753401358261464776577606903832478339589245804354508579087454162252694910844773344482611021149046116480354455617601305942523594483024855696034938579749778676423303176347347340888151177304988777650344799235158668778873655761927959467569060076066072141671787427033055911592569177110108260910246683849221598266832809998266670667496151841679241795933186305511292585313329789010406328741552521015186335892928959457352185210813706585793586655431835891916663865991383787060819588518563583863708252865070444576697776679046010833807029569591348215890550165411598509381309327227435222644862430930229016269154648515310921604137823785068951323692515705020432705359040238577897883574592171044699141069510442621429004794500509511164629247377310724138812839948146966014875865442002316316147115822535873869666457623686808443012969266429403451480342554038729339523589198931048749201138547833872346632292790389972480203315668048506830004489963474939936865962713230081702234756288583317445417488060638503911953948752192577969339481782002204627524507475657361770841692340030079253938076572038965695553701689311893564901777963171410092537042768312674959903738742767629763355851912035193112645928966314357454371342743116099157217558740986764594149942742163671005121600737607969017218138001028636328155384350303672943227090754877409301936853603040377097713234172254531565106020239802368',
		'164171010688258216356020741663906501410127235530735881272116103087925094171390144280159034536439457734870419127140401667195510331085657185332721089236401193044493457116299768844344303479235489462436380672117015123283299131391904179287678259173308536738761981139958654880852234908448338817289014166774169869251339379828599748492918775437864739032217778051333882990074116246281269364933724892342134504702491040016637557429810893780765197418589477584716543480995722533317862352141459217781316266211186486157019262080414077670264642736018426998113523445732680856144329876972273300703392584997729207197971083945700345494092400147186997307012069454068489589035676979448169848060836924945824197706493306108258511936030341393221586423523264452449403781993352421885094664052270795527632721896121424813173522474674395886155092203404036730748474781710715745446135468098139831824083259647919175273503681561172684624283384438504776503000432241604550454374116320822227191911322123484085063926350606342197146407841178028071147192533942517270553513988142925976090769695456221159699052583533011331652079347093098173086975483539274464023357456484465482927479569437320368592222760278170306076733438801098370797675711274671054970711442158930561684343135774118741594506702833147396758825015850042983343690345185995956235143825771620543546030664562647854656431302644574119873820215595718618624485232422006575550007068883734241454686368856734496265385908809403972494685137741122866896719678053937285818409751670320140501843039224040735870096889596273419106389103662095318937990625980136711988237421962315266686856089505981438440850638067589321141759499017023839596858455548192000140085142294166987063499024792681334843159790936321351919859758669569200541507612099780909705198902176026219872201715422096090343686272984351441594569506778041062663266799342793856313801540959815845788584759033248828248561586450271172777240971795656082001848115815260930521663167480173886064019118572778281516735157779555888167787064432558595410843987446497881666288423233170060413025924629950477303342180149398926073618582715358742250388958231281694757980523791263699450732952325727664209947786063982561775327638504516918570101319391698412388607603742484414748268389669129118026878969735782286841116842656410574647607524418900720328045377993386279808768990376289424757351052369393977137871998119168898493037938756635621557623138404459266598837784229325799838782026060481496865561757031839002257091802876949248392744175669112242088439883248336310597001257385980776961529351198877747193531054956881808332177946751404038228718567911769630971553915410012677600002457982207465176670752102117002773980548089696530972476439694599881281812973217265853884727906535479745854085338851105144585481994156206497436745899944877732531412541279014300324594890623941145509856940982863769834430048120562966797907114102689879364945689860493474954538422367719507882513166051007352994068319251450666676648368200564329382998758875760414259654004977261309988267319806354856051784553990936610634733375984159028722378614984450255386315585631994503350002142910493190254825610707400589976364985748467955131077971641882672895854571236368282811336220769174784720113331269084746524204124263475054112841630933586166195036115696469686075600480420563557567616835633252622327172811002146392754445051182169805284630259703542633955126179520113059629914229833688535925729676778028406897316106101038469119090984567152591962365415039646394591503830797626339246986057077758611413664914168745375266786298141171496573941614387744125843685677063619782918759823106021054037757857761587472240835040580447360544029064930412569943169729238102162312218687930203068055400275795180972382856696655279408212344832',
		'26952120750404193513632261861396278924079113968766952876432881795989952773064717517023547582462602935861988343151554953944136541732655742330344989715209032364790613993477992341015538315419979331157634679343214071675070272395846031050203990104416181306504888110677311345026982121311496900694993981896839097431416270736937100764483879691603475885150790913382009428152150677416837810025855012562604552257734907950240215423643722920841320085070969159836995287070087420490979348953287935459923512005502958342051104035727152157034501872596309497091807346831534602296739237000381981019425624127797257428795930313308723276992913170326233270996326474955890573590440983689956983091520247822856749856820965867151327989623777624602572912120388034513739443184281299447784120922392413596992920178190422947851327532150609341086404785058445916781202298840013744572277995937219260793226200101547804156066660550285603334189758481973110179753448682028957898790867330285566013316232853414644614046984553042091064852269504063338721280356430534362274115530450091697615931104386348165503547977506883150962456655568148350174378900644954808571193522853482254105207391043768826214265699942108058612042527547825232804870924409920355692212828892863846898524675998477589207679627913426446911721636181076105773289579082001255169089756739791438011116518233115849097737157581281333580664166552977845960545954723805566039806442684931440076772740156280813903751559368611983279879027372690912528122650045008005005809343307282215075359167739564986702643979470063161755939428463215178956585736792740691950620097366581157756475030693880639628028957564717506748388201460479934997075131639772156110050292383682801311501912272752251146034896908669589822188561182421548567626442405902050737934260444280400808091464891948286615235680364697810945744811260658644380752469468836186050949182213434987088443266923626493072368804684047208628736100483353498142871019538184448301514555455010870017957531222712151602595676715076786235173047351215526266074242232161952576329350969226099826143111340343868870776877764034804728697456714672752694955488362666813205601556848124569582733894829010185412078368158205633679452772740325245039148128091807268340159268190332390713116057956368833309632262724886914292004136532397863207156676423356271923268788997230183054983059464198418861749695567960894202252252428985718482550976909314126235919259431415097735142937056722180867395933758463429791251108228353506370378738883720057492392037062821199203576669507492379745663106636034141603529648250152072791795482426726847812075334671757150236305208856903602455132348260148117295696786160355352582815449613577389346464373705124445269845460300288087567879763606935329100064117928257129252417621314419004760295848797915067238834947059440036300737231196862875219470421825117891378677739697421559711211629645270252793111734441650294153890976657767935712751203970943075020427006224205578839537057762673700366813557873687195377885524377489413547417966336038733668837250885045180743821511112631400632585671166459524266991554490866854531282544830112396457787644133453547856918930267859252150666726303020818421604707816925326976802969324733095651243384448217063086179891052711416102828902776777800575003340232129652988185822691921315007186111366967324619073300429154583580635182127032049900544244545877614607444202238535981253295792569233858056209849105015633097827466842007884364230830675959668956019416191744176273361652039495912566102173045501639186081539123978052600644656251454292831580163089995965156233995220589648586920484863866827793184837626067415823731083525652620669832827156376121692170869677070642914646861380391369585780688443200170048259608955804667153883910612516726213308610915717138614799386761520965945787127839457050969293052466264047315624091114595035121852015667880592176144651859725075932198615571560789839214709994586617323564833873826223285742144757371088512442294526818322560870149959071359649404990835260598668977487201391641043166495938834420563709960733615372690590955459181016613349571195006677610310002583941425268713657639502302803341273127570270640425767468628392567564760410981218311866726323025932458512505099003963583291824276379468077888588991880595511218503954977878133134979730471068872384092380589477389509938459514027145041834618844513493123450381617418440276701681286746028194024840212540436669375081186633501602178611269022208447096228181869444834504966501924555225696054544947206129816153131308335205416097203955681491548390262577040628244205265357720428630108475623343162491975302169920528121320528957901449810640978556725429813475199342692168963973253340960441915172016945686990705723008204739699363476332881074090180937394437542797628356677310043665712274506350688717886042284479518244686074959646346047403964455232532814174782630231938398909137493083955097318419378310781800343570308447561516825855786344789474629888793013470201743911722403671905785779851302951521921132715319986089541487934077691955482266807220271193537633086592882151150308693220488018175636884029840866394624403205565579590057527962012921266347225994979367899377208497520620936129908581263574751820276075465651145907167542331242133958382307096322911199736769597988300118662979347125708251012250130548531693570552624584154336043221663856927311119801227444935344728459975797444666683477304304565466799558739413214142745624868296093021840548408108284133874907162149854774961961427584595743817051618155142326168647056011338867898006827285744302239476116375199315336737573543155497019204012481403238908281049354957812260853879180351380194157400769663673812155953436673765910376334004666292477853537867662871238308187390899260490523967153636265268799510554541618376865163856548884752741759505726850279884726397853487909152060637968595571006650653455483279642541396711835514962791318266675127774800981248980551879698727644799613397656625541551710897466658456664422128462459317246909558705620849301799110441260238810244824269149895725661100522155256385441891068194026627970889014197024276645561363292170822142584766005537947377013084637179443743260546363616665310256887925165785266204306690292438898120371494508505316637646069386959561273837790540798539752405236061152352862816042538854769587005440351339714760090162072113995509567157488906861196780594046290353099182073183613284430701084935002839752590550751562907742484518683997180734853476722099449673240962819930529932444168559077769000316841734766444816028799535673071675338228964188255114321594468218878208314581807542614629089851073096897231513024947406152399667303062490554608082062728352653787956017464487187973175435276455438354935592052167112322604392662045767918388805257954592744043455097699580368600917403323813475962872048741029144684051016765558592279266497621805828487724797698180628421670657972769274936562693990701778769245014493873070983648996255754271338304680209337765482626114795132189802426201979332758083613325788234699620295352040580332040824799909539814474800169863581704020475493961264321714819246847318743352835136103926806505544549908267250237738233812823453475627188921057250941636157067180515026083437510656852380716390684473449594460330458925616289093713297296170931498389442936383986610935498709801397585871717062958941748357812271705754879617475612535882476104585221272969815038430888621530428764313341480567925789660550772911037726992636455102674850865267643942347482222424003636645592271860976670047577546162176'
	}
]
// vfmt on

struct DivModTest {
	dividend  TestInteger
	divisor   TestInteger
	quotient  TestInteger
	remainder TestInteger
}

// vfmt off
const div_mod_test_data = [
	DivModTest{0, 7, 0, 0},
	DivModTest{0, -7, 0, 0},
	DivModTest{3, 7, 0, 3},
	DivModTest{-3, -7, 0, -3},
	DivModTest{-3, 7, 0, -3},
	DivModTest{3, -7, 0, 3},
	DivModTest{7, 3, 2, 1},
	DivModTest{-7, -3, 2, -1},
	DivModTest{-7, 3, -2, -1},
	DivModTest{7, -3, -2, 1},
	DivModTest{8, 2, 4, 0},
	DivModTest{-8, -2, 4, 0},
	DivModTest{-8, 2, -4, 0},
	DivModTest{8, -2, -4, 0},
	DivModTest{13, 10, 1, 3},
	DivModTest{13, 9, 1, 4},
	DivModTest{7, 5, 1, 2},
	DivModTest{'2103180314840157', '1631403814113', 1289, '300798448500'},
	DivModTest{'21408410031413414147401', '3130541314113413', '6838564', '2900204736088469'}
	DivModTest{
		'13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096',
		'13407807926845237209807376456131917626043958556151178674833163543294276330515137663421134775482798690129946803802212663956180562088664022929883876655300863',
		1,
		'3097359889766648542073928501435407264441214702890397900427487699558409313380739522684104737560085054384273386897573320723282547016549772350783233',
	},
	DivModTest{
		'24388660549343689307666288436614463270948472382596516055139370678271628439810393042585576900667596857198513726355043536294702186342478937800831',
		'38733748171303628844838787580045178098452927239062690602450784467058896912531690007767956310348951731921168881868406259712',
		'629648864382619361826',
		'2724578611525334851445652767465274410979805962941953382558409365935061481311529445551691298696266856092833571769883246719',
	},
     DivModTest{'1', '115792089237316195423570985008687907853269984665640564039457584007908834671663', '0', '1'},
]
// vfmt on

struct DivTest {
	dividend TestInteger
	divisor  TestInteger
	quotient TestInteger
}

// vfmt off
const div_test_data = [
	DivTest{0, 1, 0},
	DivTest{0, -1, 0},
	DivTest{1234, 10, 123},
	DivTest{-1234, 10, -123},
	DivTest{1234, -10, -123},
	DivTest{-1234, -10, 123},
]
// vfmt on

struct ModEuclidTest {
	dividend TestInteger
	divisor  TestInteger
	modulus  TestInteger
}

// vfmt off
const mod_euclid_test_data = [
	ModEuclidTest{-7, 3, 2},
	ModEuclidTest{7, 3, 1},
	ModEuclidTest{7, -3, 1},
	ModEuclidTest{-7, -3, 2},
]
// vfmt on

enum Comparison {
	less    = -1
	equal   = 0
	greater = 1
}

struct ComparisonTest {
	lhs TestInteger
	rhs TestInteger
	cmp Comparison
}

// vfmt off
const comparison_test_data = [
	ComparisonTest{ -45, 35, .less },
	ComparisonTest{ -3, 13, .less },
	ComparisonTest{ u32(352395), u32(51830), .greater },
	ComparisonTest{ u32(52395), u32(52395), .equal },
	ComparisonTest{ '574720348957234098573049571938519023857709',
		'58745908123509182375091823601928385712908347298341752397182643294', .less },
]
// vfmt on

struct StrTest {
	value    TestInteger
	expected string
}

// vfmt off
const str_test_data = [
	StrTest{ 255, '255' },
	StrTest{ 127, '127' },
	StrTest{ 1024, '1024' },
	StrTest{ u64(4294967295), '4294967295' },
	StrTest{ u64(4398046511104), '4398046511104' },
	StrTest{ u64(-1), '18446744073709551615' },
	StrTest{ IntegerRadix{ 'e'.repeat(80), 16 }, '1993587900192849410235353592424915306962524220866209251950572167300738410728597846688097947807470' },
]
// vfmt on

struct BytesTest {
	value           TestInteger
	expected        []u8
	expected_signum int
}

// vfmt off
const bytes_test_data = [
	BytesTest{ u64(0x1337cafebabe), [u8(0x13), 0x37, 0xca, 0xfe, 0xba, 0xbe], 1 },
]
// vfmt on

struct HexTest {
	// `value` must be in hex, as we get a big.Integer with radix 16, then
	// check if the output of .hex() is the same as the original `value`.
	value string
}

// vfmt off
const hex_test_data = [
	HexTest{ '123' },
	HexTest{ 'a'.repeat(11) },
	HexTest{ 'b'.repeat(15) },
	HexTest{ 'c'.repeat(32) },
	HexTest{ 'd'.repeat(5185) },
	HexTest{ 'e'.repeat(5185) },
	HexTest{ 'cafe'.repeat(85) },
	HexTest{ '0' },
]
// vfmt on

struct PowTest {
	base     TestInteger
	exponent u32
	power    TestInteger
}

// vfmt off
const pow_test_data = [
	PowTest{ 0, 0, 1},
	PowTest{ 0, 1, 0},
	PowTest{ 1, 0, 1},
	PowTest{ 1, 1, 1},
	PowTest{ 2, 0, 1 },
	PowTest{ 2, 1, 2 },
	PowTest{ 2, 5, 32 },
	PowTest{ 2, 10, 1024 },
	PowTest{ 2, 30, 1073741824 },
	PowTest{ 2, 234, '27606985387162255149739023449108101809804435888681546220650096895197184' },
	PowTest{ 2, 524, '54918381281044877719855206392651145738155482401146443275155707673484345467181248416980477125291636439818370491131846864296975903997733150500592226328920457216' },
	PowTest{ 2, 291, '3978585891278293137243057985174566720803649206378781739523711815145275976100267004264448' },
	PowTest{ 2, 13051, '55267956948146482939580690892144167523198080345777838207973892310290788736821578114330455608899403999039109810492889769112675765371767842822434294904209432777633054910495035098236995390194172097907719098491142950680893121170415521376299250142695723393227633360829843822866024641522563385984082711736391348667978440753913719338262829073043347247299392139063557930790932287363651577574134082253690763995791163252208415844758727346329281304595424562991322680879863770722706799961809876056054813814521080566806686543718660613598426151803438498674178140121315919034857314115503781267190616565875833106631659285123886667080327050174176636018357664222092316439777145540128647880814336995055642164733977751410563822190384321689041057299634727749812974144023207025653904438780374867988942510987313912358915642077631661267839921263001062107729173356916478717702317027506423498272334490092958377684733699662429071107215486273972618250534115869723283498114137145525373906475082833289104669492127120264073453925068828669125794548775264089233042803009595366761575381131720150020416662597433270991992738498853512916968911947303026796659580500368762437079002069661349769285545784372450396095376496629526120146056228969588758257289220372378463001533895184835727768908852564233327092981929411751106985223047814350329661006786989543912993534105514927316542621884655977620130711246926843567109456472355504038497809114457931293164130666363146093971664611970414478485192994816264742799354431903294883107927606299200191395563965045258006700385533997784569469661002395464091760511030079955508794507716517333922113296290807049250301483689712907877303498967096232669748824940257740874215641972642675515304831959934847559373172772025875939941676740275689817054162918846662455567085919928556650978239087803483530882408322645489433079587537294621171822004369279659604911446107164265409771411479042191057214450986176256578104398112366947709868794481776078240442638184240046590399307658325666682824402555546582169125084299171911366515003536406493880562467793738217233554231178610461637407108387422104493358650812565981939865004194724312308819851360505832016659131404286536166604042995985362843053197530692653760538388205506347898194204185268035169011980847365832662902833167362084522724032944503999606348026648228492541892525660287991575613769500299950657228084617208982541726107251394954812792421965613075539830944521759805581201863306109230481535735866977702920938163637191044218917218763676996478413703527738808285760128085267402333007136279283870165611587883351595579551530437487879301447035074519559776804970191650066388050122761542282202772884141794482588913487773583646082244648646898935682167457258599202486566745556266587599528210145725708324833027469913664602498185234663551855895508091756784116786760256088764788750159984191050146275837122761351322740020869396023016337700936855961260331330031678574208143275974341369638055331776401934895373348591440122433244331646746067969385005236926872015898048323445768868147713435873976237988151319143506783129013204847868879150394120372376677277312144782189330256123263292237715700439809503932239415509520929779856708018666527067600827221597869399175438321388641981165828368557419771140117333070030872143102607788421073131616871657178020327435898081376870580959579623464843234800465871796556467456341474610533391530095305196315887535933316836459037786625667180354374811843995688474490608169113180680143676925870456310071925085465713774179009107449991929491343540484244181606094673172473788660554675839157004904589906389801922612312350223513086754383162398737177774230411158150377305076748192396441454734336654918968445280484743879759859090769539002965788922965135895758979301734303194298909826556775859142046683115828058122817136236184480127270446495870009273426474586242661860904296452193946364822434632085953525238418258226591281397400949183681177585810194950485799542968112294068369136156497511211228725248' },
	PowTest{ 324, 315, '66325146064916587705822805477951823674769212922003325230500180789514487101799702287247301347816140714887582527826252837635296749781071351621748491469338347097923896026211183517655658952346069454893422558286798338709431368762851475568899541999504754550056265493269010870696623999709399529395247064542825851568385196637089440522882877102429945439977107582295420418108331098961838419917230847980056560488541780255425015021238743932289115066701337398107639567748102191005710201353615093246958907555634902309636451244444952203735074916066229982498598205421944122042066749035283837586883383420374291325389757869347147357807188516650352693616763867685354382631931356465247637321960345782811272139101785279798666504361229957479336436466489780129445016691164329417001378480690804715301830926348058624' },
	PowTest{ '68973377060666327208300998134976245269331422613575559102002431189859063751444117873216302679385447519268197493634614796410525545235779538750217378947422409274212222649954053354836156', 40, '35258157541008739895331135586163782978774260107060350863053496129803595902499520940913245496659764125837663081609116693664859066121240222710455090772654236305161593582934388795922429749725757888593191060785569873278223392217676911081371575408698209198487574208133504092628962419627719435594361886665948512724378730193034883682168393683858735816474842100358088758399284368135640873191297579994494530855391610253450197112507337023973260390114533551942575098377704162567050376536430239009068399198141851190687786692855878006471015617730177140564368490211125304311492626663371442064896009452985346147238789927023952155765874191186509560387099879963058580458175561206837610198181475959286262651094184535935843622210514022579661392260730979033525048986082578378757345674162044090708247493623847265486608083275091608623071230279318646779316496782411478544030608676817377643527831062728898442877397153923451755987019024165148269190403334041384095965099409973404146520908147697493051017569834287683508859619614820718839901473820225092359044663170397185665222505521573782264521807940918163830187995079966398797834892374540329644161011839047312660408041075233827338195607721484103616473925700064580565891872491802099275924411222757546424787635592046987870959737279307319356334181603750301494352434527308393706898772379215484237398245418863149959467744064471526937704836205865867678040592702295144785801441309292006081240708835717111188736116077625711594150435701058724546928000620650885222066533349258673109739859759612800975406051665452593729572474029949396850025034721391155268272910460099672143460177826856963197730677959657469514888519160035227448297269382534435799272102328415501312356111831947752575670395475105022420187733034171502887359638152057876379771261999121543335479247633748144423214477698449199446169433490219980784078516768935903866137328947352936172402921848772002674322630245635026231629454706048753547546902225014320540104977155736944657399787940439035277957092279432489442361800063891355739406363001782622680936832010543170656715775452062089081852640884272056572152042908273232284891160722405506506925047900433631369352240575822425084000954380503324509277410828459755147240727523792066016952349310027090166657648299162430936093103120333183134330248812717816439403194436580527262279045316890050092161084522990205107250830319663209486820407463781212079072171125202655959768122491168090453120012969830867004575480551791284934079004033495761485325184899900038803474124601794212496136498280996063010402993132647266142814962192181619151827932124894236921088644522787656602462050326681805844438219230755707199226244584366270014878488134597806515533702003407174379138958404132228268468415855937695923909093324159910887747556292181906257010119373908909281031098335560145512862280651673879872429356095545191263033441020104833977186041802651653142739004325260453065487714226086302334925470018494814279647772696732751413492938129340193390870371914405132971752944771382425547764289488463024568565047205504469195296554979731615888034588174368312122402232599112594230523742220097645109619918997486658429331785718355443479680146829664055646997657939426194000103378913037286846713039443955792103079259450246916434767428300921600590858128004218244953067853605711134269179529138347808509232974732360192374463207085903368535685042319215946964616538267824251199799335578316284176334931243032435271890535306860625400974970800196067356950499429899623903038882907645186739157691937393868001954217068677405564876964259777068576274955960434304735331332727337942605330662700571524428729266514174137948899430401136194700301206200551515499664922638963028270893302781587131748991793976526030657152281703854200233227924967926571276661994874579099755225676717805006216569595520566828236321367761203653020465515401663214232518761474223110777886389720199103747449349499503400895567044624612530615359244422254804356461625965858659146045123680314611311068802319473327814245022783376966016661309117610975157629715943310597824424800462948268112526010321134293021657131436472752011710620253048339957169295446502441751862148811884121265645084802972835434430500666554560667426728304121819451042399317183881953483237660080276310900310609399239782487398889813072240297043891794998893001786233968869912478411537501683017172187740347782175947175330986012037410594509842385173934376073883704392390066195094586380644822566323337063806458420270229827713462151670514123181768373835781491371536706582982089663589356740349371026605036928057179599547510869011654375677928737943079864386098501933754834569076969459522907991122865834472316075011973279443310747045576723382195820376147552983791746734829752811505837765374961937584859088696438357582609441168579224373232538884336186944109656062668354958262471022386307605217481710783595873812958322692301637767626905751159343436670100901639626281237260581520402478166789720378200977977591043846005303066270994585484308872635398698206784922087791315869659668470550750672041440181846921937878737954369397741595712732557836089455119269549939304717990844018805341426733137219366976467073055703514345869726491666687917740218342964217322837128666044618309225468654622198231241735033740025000833039365889040210467381631582635008903317248408687515878944562462103899122853122282077536393859736678126798284896936745206987705406162201111434866485708471709121620748864731821841498499097932663197004613917962363847058188708935507962599345315904755192312885153454959868456584090394953490529701708225758187924021653717046235748081644499911269567590535014838235292295638849624380239182552648037518233234630924354382791335743589786044871629805970609844860052222008562149922586920233688221038240158947965090122365291307769963243469486471480976812917614890560320724900635565696327855056530135961774334692292338693195704454096038710058676180521224229217340225496509476508946611845834909161932831898098821430336348772505879016381899870043035683249316508108617843133439016918107763134987853201904389395477535249692909938456858665886155150195584515422711040259472814260855939483496834006050935205671281977481531908760417170523135516028527539444163160573194971206959625166833408764832574810255735634834363957899317195483566233828249891102020662519608925798051078615457621971822365495901117747375145048348614866478147644564817801751372420581094557535616477014993403293835622275791359197059201243272901787903487483825695988147058737185860181150381743018939858230502180587316663351024125733956328873574985787891695924518737336301071771593783442839325168387680903413878668606904467043759169383257006087574325785908578823397586231203787496335131359918746993718914006871027887598302839973090822047886906908431573569039736038250163656132301560418543891406517287043442644328121923996383111070947282060547074035037933135808930649423603110117360018001877349840800296558270695890794753087083525850557161190187608610387510161000273695896242816085985017009465480555075198416753288507556316216285114056684935945988548526597279887832288588727265282867869907650516070481891621446962371494964005298779179376792868773282807097284115930818770799203719816032512376608176221517386343418001080528568223383975802920001284696679468308086909698604190274805636772843836377041111569722570010440042124020486157215597592576' },
]
// vfmt on

struct ModPowTest {
	base     TestInteger
	exponent u32
	modulus  TestInteger
	power    TestInteger
}

// vfmt off
const mod_pow_test_data = [
	ModPowTest{ 0, 0, 123, 1 },
	ModPowTest{ 0, 1, 123, 0 },
	ModPowTest{ 1, 0, 123, 1 },
	ModPowTest{ 1, 1, 123, 1 },
	ModPowTest{ 324, 315, 632, 512 },
	ModPowTest{ 65, 17, 3233, 2790 },
	ModPowTest{ 2790, 413, 3233, 65 },
]
// vfmt on

struct BigModPowTest {
	base     TestInteger
	exponent TestInteger
	modulus  TestInteger
	power    TestInteger
}

// vfmt off
const big_mod_pow_test_data = [
	BigModPowTest{  0,  0, 4205,   1 },
	BigModPowTest{  0,  1, 4205,   0 },
	BigModPowTest{  1,  0, 4205,   1 },
	BigModPowTest{  1,  1, 4205,   1 },
	BigModPowTest{ 23, 35, 4205, 552 }, // passed to mod_pow
	BigModPowTest{
		'5155371529688',
		'2791323022555160232601405723625177570767523893639864538140315412',
		'108959927459825236754563833',
		'26860526814751021488886966'
	},
	BigModPowTest{ // odd modulus
		'352374589237450928347609812740958719304509123759871239856523745782375908723095729758275893947985713250128357912349123412939358823582385385198351236046127834612374812370491327508137250913279785120956123875610235871239857198203659081236598012735981327096129836712397538257324587324658973246586212305713209851290386517823650983',
		'1435987139846732486843289483294829493285238539385476982375980650172394182703846128975612083751298035612365812378908579834576456739458768754674674758467957697513267415734673649713598712634987126359872685236563875',
		'235091287508475298347528357901372598012305123512513252139683276908769284375274983274732895287478365817326581273509823651087861235876123563725193512827341395182375612384723587131912725187352562171235812387132578235385239913578132684794719844871326571632561325617256983275689175687132487134894717895941563769587165871727358791326578126587261589732165781623578921653625871256781326587132658716237561235612783569812358791263985688921356634756374561398756298576128463875627',
		'169366899917096971139137080261692248176119100321982279129907315595573960531869689311776921667033660828498254917762241531493510090131310371752611041591194730984721766392649610729748330695093443476931010397820703902902374473806912248240019857777647140275706106146415293419050004306619925031697942412075960435433660980502714238024766862370671258678169869169308956145487178274009104771385352022837969419172440632584754050020898915411115587200113298960058827089497449758704',
	},
	BigModPowTest{
		'65963856903485603485069234860923480925798172358172309571298347102836578126398512837409812375712637895612379856123981237510298356120347129803401236571623978561287347129837563453245983475983457439573985398456987356198236481727340813259182735619827356189723658763578623842342348791856178236598273498213492641265929375983589324658972364587869871263587612387568767345727346273647235738786247865198746132879461234613284823467',
		'83272598179813257612837472873648237598405840629839475914921364871236813258573298457912734897123942134273981',
		'5839857294085157278513295172390857198203571235213752396329429342385198326512374982374982394818327590816263059612397512983479812378951235123571239857908674389573485791835127834617823648791263587321501273958734987520983475818586128374612837589734985729073459081628387561982736547958729875923652356138756183576',
		'1473628912328925119498300555459646092229919432628304743927027840523966896206312866878166443381090567655363186687840805386391819767096022910509388879763843632740700147538366282034781700814905320520871339523971198789410048087451530293781098724024347130773477767285944506944257502250353223975013799044669645147',
	},
	BigModPowTest{
		'113242346235324852305823906832570234458325884382848882352385183957109823579028553482572308468203945823946234096234056990567506978059607985823049523458273598234750329857',
		'8' + '0'.repeat(304),
		'538232475982347092375235252304678234670293486732980467394932151374571938467459586739087429813752353459823475982375983259823495510986571430996238476587342658172851235761398456398765813459801238751782351252542389712789568712342749837482748292340120120350125012352859821657823501275012365123985761983576123561273561257632958127659327160124712350123571029356123512507123598321797',
		'192406008638594029999856291470760872362212741932343638540342189789173751505083836385843995643278520411152869906156437055678588013127671381619800101872065097151880787029771615331116606406595932983669815757450573569058422413443800383057849205750667577751024330669200452034408252515262931175662782786664172617789499914619948520343146045783354828154425927051367644302499369000252',
	},
	BigModPowTest{ // even modulus
		'235823052395732458137502345873250',
		'9247324572804102889565555777311914057954687482673431192869682151395651003606366864848904841770165182604035932529621174486515688424932060959148379649412557',
		'2176617445861743577319100889181907668374255538511144643224689886235383840957210909013086056401571399717235807266581649606472148410291413364152197364477180887395655483738115072677402235101762521901569820740293149529620419333266262073471054548368736039519702486226506248861060256971802984953561121442680157668000761429988222457090413873973970171927093992114751765168063614761119615476233422096442783117971236371647333871414335895773474667308967050807005509320424799678417036867928316761272274230314067548291133582479583061439577559347101961771406173684378522703483495337037655006751328447510550299250924469288818',
		'442997670902441289693502035236411859724060788065895656400579052337406446773758010436855122951259016429941998670112046510440662262181776245572088822784133641469508278250883828352296420961829921453124482851450238472747959697964344812370952273954391788494014188845640003786259215718720844436373044245757220429613176387487778233231542432645946351180509817097194411903946161272789482180797502735809791321387092632573236334305080001390892058454801700346356574718281589228939135660037060121182304974907075601193595994210348704718150369101358547875357900995290428579291079564736470284970163062216850888677989344123412'
	},
	BigModPowTest{
		'5155342534532472457235424353715296885321784212092346234575235718572938457284759829789708703754094283682345782309123940810923850923745723498672398459023845028309402347698798128209480234598716824503042159',
		'86088201503667039039649712985497870124991029230637396538140315482910296196688861780721773488400937149055855947456947824680518799310618149812585881185273945728945238450238465982768132749812308932579342985729345798328459832591982374981237590923882894732852358383128938192888912389148132163716923461512177401900495710673973552425181964932538140315421936569702910921834517138450159290932430254268769414',
		'274591906405224388599271723580726658164960647214841029141336415219736447718088739565548373811507267740223510760319632557286907774120057322163752385728943578236484780326508234652347012734098132747829056238742677853836742172732148487951998402235107603196866575250296113164460906849287604912497386435248807205228608',
		'191409711082233170599206818399072245570776992384487887400529042633340865718475272702984694979757086140971619519330041885966232600204343618098862571914303534164078578922423233100444505069197147657365390879382972696958855409999020160689093198793125749417593529720182526801136320146027275209623807723638007207345057',
	},
	BigModPowTest{ // power of 2 modulus
		'853475230582304956623462734587234857',
		'583752847502934572695871320598123057810835791832765601237490813250912360591237591247132543095792347598327957137481023974819237887128577123758127912735720912735708362178561027835610235610256231201472309873219800321951',
		'31195165372897259196222538898096203590151924108450147950531565441852619837316692843188389598728651769482088968838700984268947453885587967878549286444999755742573423371025356539077075265986419171772426279084559025861175301940492273427120221755816136975739916983004778387946699939545354293487098252428954036286183995782377175227121587657233553706589448547148066273280603243167958729707736664649187444136702017299877489729451997277875868782399735511520086969969766278182145454186690598629675562422923132555707758646587702550600894625696538109646366308973392363200122154242784576162149305816215109893613161331026672647000825615987247035266514313689413563779184515427920269935280569035788081552413007563772309295149800172031645681720569680154349893907395864528243629654386620034655445226295834594630792819545156798270599481573436039129275439653984521135652249263653985326577886990615665734998585216581730937090703518997669223802429711292740491797911117308280939507973715877108492303860661291987529284719391551256912380499409630332506454532263266457209921483705507359152839264852808182519011100934922492651373859423833024010283468753147686188675294998119637462200763443029190704825719342806119404339670408160210011918981038977425180213726646978883378058838510330816291941879581568740273684084511318422175006728346276489384220596694727036836687670632486602655240593463885077059375085482211864761344849868123074687509143827139683659102930877963676911995751113159944160296419825178911962487549670296207457410515598040046860567719116506974858703739531721991704589155513182996455827177472',
		'20080128881481836026329919458482291336427826856257996902940216961274769492432457342329585911526680598599706497937330675336231322550089070961997878231160797014417182095610964306078005177657705895303701167263611016504813896879268670353690809857529479048652197026092060293580162938995900771157020773980149060390600886988165389386800313399935681668574561849644795370126640258861886083152431680309682414362667647047408205246634496700184520404072535696087062725321498879508195864728319264953502905783599235208616928912295007582161378604427602444176983900856363236858555001132922259491209136145654862306503211818341793436738181575298025051779368026867674815572620689517665845691581156037531328681002192885908572782500210185856071870996928958700199226442991667291661898788475465881534872952976564959204125435567408766407069080824764398534937188392006557445009391997597405999602710062336419706104598663078108578494090878260551511868925451048198114479011315931259263368212342695453474607592164864833976245439378166385649596428707473508482940426102862136582304433403471613967149235623865180698593404828164563801111816849132293956996556247415009648932020221786934682827799748481777622180801590275002765776928805756187584952776044614940158088391767782343033313716059721086499569092199761880797791493764006487948292742803823944731896556184944138299575510183812680359579022267096795084742403276965131310267236257021618824374001979653996305168583849734973984410291953747451176667816227487401602863864660642232048020325795772190251487050535547981550465960228478297407995702324941118877701015321',
	},
	BigModPowTest{
		'919883988246145022313927375667609631628',
		'11258911920206359584',
		'10961431611736082634',
		'3987973861467626556',
	},
	BigModPowTest{
		'319978239103006490429056663053051872523340306',
		'3450311374119871456',
		'16136980157234240016',
		'6495281920355297920',
	},
	BigModPowTest{
		'6572721605915324110691520672890333438736158723396',
		'8598931276445806048',
		'6234270195866676796',
		'2267960990325264040',
	},
]
// vfmt on

struct GCDTest {
	a        TestInteger
	b        TestInteger
	expected TestInteger
}

// vfmt off
const gcd_test_data = [
	GCDTest{ 0, 0, 0 },
	GCDTest{ 10, 0, 10 },
	GCDTest{ 10, 0, 10 },
	GCDTest{ 1, 1, 1 },
	GCDTest{ 0, 1, 1 },
	GCDTest{ 0, -18, 18 },
	GCDTest{ 51, 22, 1 },
	GCDTest{ 98, 56, 14 },
	GCDTest{ '67116917544110', '60943431483592', '6299482' },
]
// vfmt on

struct FactorialTest {
	base     TestInteger
	expected TestInteger
}

// vfmt off
const factorial_test_data = [
	FactorialTest{ 5, 120 },
	FactorialTest{ 100, '93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000' },
]
// vfmt on

// for left_shift and right_shift
struct ShiftTest {
	base     TestInteger
	amount   u32
	expected TestInteger
}

// vfmt off
const left_shift_test_data = [
	ShiftTest{ 45, 2, 45 * 4 },
	ShiftTest{ 45, 3, 45 * 8 },
	ShiftTest{ 45, 4, 45 * 16 },
	ShiftTest{ 45, 5, 45 * 32 },
	ShiftTest{ u64(0xabcedabcde), 20, u64(0xabcedabcde00000) },
	ShiftTest{ [u8(1), 1, 1], 56, [u8(1), 1, 1, 0, 0, 0, 0, 0, 0, 0] },
]

const right_shift_test_data = [
	ShiftTest{ -8, 4, 0 },
	ShiftTest{ -8, 40, 0 },
	ShiftTest{ 45, 3, 5 },
	ShiftTest{ 0x13374956, 16, 0x1337 },
	ShiftTest{ [u8(1), 1, 1, 0, 0, 0, 0, 0, 0, 0], 56, [u8(1), 1, 1] },
]
// vfmt on

struct ISqrtTest {
	base     TestInteger
	expected TestInteger
}

// vfmt off
const isqrt_test_data = [
	ISqrtTest{ '32653970479009599018236258903443284683789766179879955366041757982300361890625826551918485225', '5714365273502351023665817936982376512387569235' },
	ISqrtTest{ '1234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567654320987654320987654320987654320987654320987654320987654320987654320987654320987654320987654321', '1'.repeat(97) },
]
// vfmt on

struct BitLenTest {
	value    TestInteger
	expected u32
}

// vfmt off
const bit_len_test_data = [
	BitLenTest{ big.zero_int, 0 },
	BitLenTest{ big.one_int, 1 },
	BitLenTest{ u32(0xffffffff), 32 },
	BitLenTest{ big.one_int.left_shift(1239), 1240 },
	BitLenTest{ '4338476092346017364013796407961305761039463198075691378460917856', 212 },
]
// vfmt on

struct ModInverseTest {
	value   string
	modulus string
}

// vfmt off
const mod_inverse_test_data = [
	ModInverseTest{'1234567', '458948883992'},
	ModInverseTest{
		'239487239847',
		'2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919',
	},
]
// vfmt on

fn test_integer_from() {
	for test_data in [
		// add integer_from_..._test_data to this array
		integer_from_int_test_data,
		integer_from_u64_test_data,
		integer_from_bytes_test_data,
		integer_from_string_test_data,
		integer_from_radix_test_data,
	] {
		for t in test_data {
			assert t.expected.trim_string_left('0x') == if t.expected.starts_with('0x') {
				t.value.parse().hex()
			} else {
				t.value.parse().str()
			}
		}
	}
}

fn test_bytes() {
	for t in bytes_test_data {
		r, s := t.value.parse().bytes()
		assert r == t.expected
		assert s == t.expected_signum
	}

	mut bytes := []u8{cap: 1024}
	for i in 0 .. bytes.cap {
		bytes << u8(i | 1)
	}
	result, sign := big.integer_from_bytes(bytes).bytes()
	assert result == bytes
	assert sign == 1
}

fn test_is_power_of_2() {
	for t in is_power_of_2_test_data {
		assert t.value.parse().is_power_of_2() == t.expected
	}
}

fn test_is_odd() {
	for t in is_odd_test_data {
		assert t.value.parse().is_odd() == t.expected
	}
}

fn test_addition() {
	for t in add_test_data {
		assert t.augend.parse() + t.addend.parse() == t.sum.parse(), 't.augend: ${t.augend}  + t.addend: ${t.addend}'
	}
}

fn test_add_sign() {
	for a in -10 .. 10 {
		for b in -10 .. 10 {
			big_a := big.integer_from_int(a)
			big_b := big.integer_from_int(b)
			assert (big_a + big_b).str() == (a + b).str()
		}
	}
}

fn test_subtraction() {
	for t in sub_test_data {
		assert t.minuend.parse() - t.subtrahend.parse() == t.difference.parse(), 't.minuend: ${t.minuend}  - t.subtrahend: ${t.subtrahend}'
	}
}

fn test_mul() {
	for t in mul_test_data {
		assert t.multiplicand.parse() * t.multiplier.parse() == t.product.parse()
	}

	for t in div_mod_test_data {
		assert t.divisor.parse() * t.quotient.parse() == t.dividend.parse() - t.remainder.parse()
	}
}

fn test_div() {
	for t in div_mod_test_data {
		assert t.dividend.parse() / t.divisor.parse() == t.quotient.parse()
	}
	for t in div_test_data {
		assert t.dividend.parse() / t.divisor.parse() == t.quotient.parse()
	}
}

fn test_mod() {
	for t in div_mod_test_data {
		assert t.dividend.parse() % t.divisor.parse() == t.remainder.parse()
	}
}

fn test_mod_euclid() {
	for t in mod_euclid_test_data {
		assert t.dividend.parse().mod_euclid(t.divisor.parse()) == t.modulus.parse()
	}
}

fn test_mod_sign() {
	for a in -10 .. 10 {
		for b in -10 .. 10 {
			if b == 0 {
				continue
			}
			big_a := big.integer_from_int(a)
			big_b := big.integer_from_int(b)
			assert (big_a % big_b).str() == (a % b).str()
		}
	}
}

fn test_div_mod() {
	for t in div_mod_test_data {
		a := t.dividend.parse()
		b := t.divisor.parse()
		eq := t.quotient.parse()
		er := t.remainder.parse()

		q, r := a.div_mod(b)
		assert q == eq
		assert r == er
	}

	// an extra test for checked division by zero
	if _, _ := div_mod_test_data[0].dividend.parse().div_mod_checked(TestInteger(0).parse()) {
		assert false, 'Division by 0 should return an error'
	}
}

fn test_comparison() {
	for t in comparison_test_data {
		a := t.lhs.parse()
		b := t.rhs.parse()

		assert a == a
		assert a <= a
		assert a >= a

		assert b == b
		assert b <= b
		assert b >= b

		lt := t.cmp == Comparison.less
		gt := t.cmp == Comparison.greater
		eq := t.cmp == Comparison.equal

		assert (a < b) == lt
		assert (a > b) == gt
		assert (a <= b) == !gt
		assert (a >= b) == !lt
		assert (a == b) == eq
		assert (a != b) == !eq
	}
}

fn test_conversion() {
	ten := big.integer_from_int(10)

	mut n := big.integer_from_u64(u64(-1))

	mut digits := []rune{}
	for n.signum != 0 {
		quot, rem := n.div_mod(ten)
		digits << rune(rem.int()) + `0`
		n = quot
	}

	assert digits.reverse().string() == '18446744073709551615'
}

fn test_from_and_to_hex() {
	for t in hex_test_data {
		assert (big.integer_from_radix(t.value, 16) or { panic('Cannot read hexadecimal') }.hex()) == t.value
	}
}

fn test_radix() {
	number := '1234567890123456789012345678901234567890'
	a := big.integer_from_radix(number, 10)!
	for radix in 2 .. 37 {
		str := a.radix_str(radix)
		b := big.integer_from_radix(str, radix)!
		assert b.str() == number
	}
}

fn test_str() {
	for t in str_test_data {
		assert t.value.parse().str() == t.expected
	}
}

fn test_pow() {
	for t in pow_test_data {
		assert t.base.parse().pow(t.exponent) == t.power.parse()
	}
}

fn test_mod_pow() {
	for t in mod_pow_test_data {
		assert t.base.parse().mod_pow(t.exponent, t.modulus.parse()) == t.power.parse()
	}
}

fn test_big_mod_pow() {
	for t in big_mod_pow_test_data {
		a := t.base.parse()
		e := t.exponent.parse()
		m := t.modulus.parse()
		r := t.power.parse()
		assert a.big_mod_pow(e, m) or { panic(err) } == r
	}
}

fn test_gcd_vs_gcd_binary_vs_gcd_euclid() {
	for t in gcd_test_data {
		a := t.a.parse()
		b := t.b.parse()
		expected := t.expected.parse()
		assert a.gcd(b) == expected
		assert a.gcd_binary(b) == expected
		assert a.gcd_euclid(b) == expected
	}
}

fn test_factorial() {
	for t in factorial_test_data {
		a := t.base.parse()
		r := t.expected.parse()
		assert a.factorial() == r
	}
}

fn test_inc_and_dec() {
	mut a := big.integer_from_int(2)
	mut b := big.integer_from_int(3)
	mut c := big.integer_from_int(4)

	a.inc()
	c.dec()
	assert a == b
	assert b == c
}

fn test_left_shift() {
	for t in left_shift_test_data {
		assert t.base.parse().left_shift(t.amount) == t.expected.parse()
	}
}

fn test_right_shift() {
	for t in right_shift_test_data {
		assert t.base.parse().right_shift(t.amount) == t.expected.parse()
	}
}

fn test_bit_len() ? {
	for t in bit_len_test_data {
		assert t.value.parse().bit_len() == t.expected
	}
}

fn test_mod_inverse() ? {
	for t in mod_inverse_test_data {
		a := big.integer_from_string(t.value) or { panic('Could not read decimal') }
		m := big.integer_from_string(t.modulus) or { panic('Could not read decimal') }
		r := a.mod_inverse(m) or { panic('No multiplicative inverse in ring Z/mZ') }
		assert (r * a) % m == big.one_int
	}
}

fn test_isqrt() {
	for i in 0 .. 1000 {
		a := big.integer_from_int(i)
		b := big.integer_from_int(i * i)
		assert b.isqrt() == a
	}
	values := [
		TestInteger(314),
		'213149',
		'2198614',
		'318014',
		'1000000000',
		'1000131039410',
		'2148170394871039847019843349714981',
	]
	for value in values {
		a := value.parse()
		b := a * a
		assert b.isqrt() == a
	}

	for t in isqrt_test_data {
		assert t.base.parse().isqrt() == t.expected.parse()
	}
}

fn test_bitwise_ops() {
	a := big.integer_from_int(1).left_shift(big.digit_bits * 10)
	b := a - big.one_int
	assert a.bitwise_and(b) == big.zero_int
	assert b.bitwise_xor(b) == big.zero_int
	assert b.bitwise_or(b) == b
	assert b.bitwise_and(b) == b
	assert b.bitwise_not() == big.zero_int
	assert big.three_int.neg().bitwise_com() == big.two_int
	assert big.two_int.neg().bitwise_com() == big.one_int
	assert big.one_int.neg().bitwise_com() == big.zero_int
	assert big.zero_int.bitwise_com() == big.one_int.neg()
	assert big.one_int.bitwise_com() == big.two_int.neg()
	assert big.two_int.bitwise_com() == big.three_int.neg()
}

fn test_get_bit() {
	x := big.integer_from_int(42)
	assert x.get_bit(0) == false
	assert x.get_bit(1) == true
	assert x.get_bit(2) == false
	assert x.get_bit(3) == true
	assert x.get_bit(4) == false
	assert x.get_bit(5) == true
	assert x.get_bit(10) == false

	values := ['1001001001001010010010100100100101011101001001010',
		'1111111111111111111111111111111111111111111111111',
		'0000000000000000000000000000000000000000010000', '1110010', '0001001']
	for value in values {
		a := big.integer_from_radix(value, 2) or { panic('Could not read binary') }
		bits := []bool{len: value.len, init: value[value.len - 1 - index] == `1`}
		for i in 0 .. value.len {
			assert a.get_bit(i) == bits[i]
		}
	}
}

fn test_set_bit() {
	mut a := big.integer_from_int(32)
	a.set_bit(1, true)
	assert a.int() == 34
	a.set_bit(1, false)
	a.set_bit(3, true)
	assert a.int() == 40
	a.set_bit(50, true)
	assert a == big.one_int.left_shift(50) + big.integer_from_int(40)
	b := a
	a.set_bit(100, false)
	assert a == b
}

fn test_integer_from_bytes_ignores_potential_leading_zero_bytes() {
	bint0 := big.integer_from_int(0)
	for j in 0 .. 10 {
		assert bint0 == big.integer_from_bytes([]u8{len: j}, signum: 1)
		assert bint0 == big.integer_from_bytes([]u8{len: j}, signum: 0)
		assert bint0 == big.integer_from_bytes([]u8{len: j}, signum: -1)
	}
	for i in 0 .. 10 {
		bint := big.integer_from_int(i)
		nbint := big.integer_from_int(-i)
		for j in 0 .. 15 {
			mut input := []u8{len: j}
			input << i
			assert bint == big.integer_from_bytes(input)
			assert bint == big.integer_from_bytes(input, signum: 1)
			assert nbint == big.integer_from_bytes(input, signum: -1)
		}
	}
}

fn test_pow2_is_power_of_2() {
	for n in 22000 .. 22010 {
		assert big.two_int.pow(n).is_power_of_2(), 'pow2: ${n}'
	}
}

fn test_bytes_from_bytes() {
	input := ['0', '9999999999999999999999999999999999999', '783086277830859384',
		'890810171456467012368983335296321559']
	for n in input {
		a := big.integer_from_string(n)!
		b, _ := a.bytes()
		c := big.integer_from_bytes(b)
		assert a.str() == c.str()
	}
}
